using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace Speedball2 {
  public class Pc1 : IDisposable {
    public int _resolution;
    public Palette _palette;
    public Bitmap _bitmap;
    public static Palette.PaletteLookup PaletteLookup = Palette.PaletteLookup.ST;
    public byte [] _bytes;

    public Pc1 (string filename, Sprite.MasksEnum maskEnum) {
      Load (filename, null, maskEnum);
    }

    public Pc1 (string filename, Palette palette, Sprite.MasksEnum maskEnum) {
      Load (filename, palette, maskEnum);
    }

    public Pc1 (byte [] bytes, Sprite.MasksEnum maskEnum) {
      Load (bytes, null, maskEnum);
    }

    public Pc1 (byte [] bytes, Palette palette, Sprite.MasksEnum maskEnum) {
      Load (bytes, palette, maskEnum);
    }

    public void Load (string filename, Palette palette, Sprite.MasksEnum maskEnum) {
      byte [] buffer = ExtensionByte.CreateFromFile (filename);
      Load (buffer, palette, maskEnum);
    }

    public void Load (byte [] bytes, Palette palette, Sprite.MasksEnum maskEnum) {
      _bytes = bytes;
      _resolution = bytes.ReadWord (0);
      if (_resolution != 0x8000) {
        throw new Exception ();
      }
      if (palette != null) {
        _palette = palette;
      }
      else {
        _palette = new Palette (bytes, 2, 16, PaletteLookup);
      }
      byte [] bytesDecoded = Decode (bytes.Extract (34));
      _bitmap = Sprite.CreateBitmap (bytesDecoded, 0, 320, 200, 4, Sprite.ModesEnum.Scanline, -1, _palette, 0, maskEnum);
      //_bitmap.Save ("toto.png", System.Drawing.Imaging.ImageFormat.Png);

      //string pngName = string.Format ("{0}.png", Path.GetFileNameWithoutExtension (filename));
      //_bitmap.Save (pngName, ImageFormat.Png);
    }

    private byte [] Decode (byte [] bytes) {
      byte [] bytesDecoded = new byte [320 * 200 / 2];
      /*
         * decode packbits
         *  0 ..  127  n+1 literal bytes
         * -1 .. -127 -n+1 copy's of next charachter
         * stop decoding as soon as cnt bytes are done
         */
      int cnt = bytesDecoded.Length;
      int src = 0;
      int dst = 0;
      while (cnt > 0) {
        int cmd = bytes.ReadByteSigned (src++);
        if (cmd >= 0) {
          /* literals */
          int i = 1 + cmd;
          if (i > cnt) {
            i = cnt;
          }
          cnt -= i;
          while (i > 0) {
            bytesDecoded.WriteByte (dst++, bytes.ReadByte (src++));
            i--;
            if (i > 0)
              if ((dst % 160) == 0)
                throw new Exception ();
          }
        }
        else if (cmd != -128) {
          int i = 1 - cmd;
          int c = bytes.ReadByte (src++);
          if (i > cnt) {
            i = cnt;
          }
          cnt -= i;
          while (i > 0) {
            bytesDecoded.WriteByte (dst++, c);
            i--;
            if (i > 0)
              if ((dst % 160) == 0)
                throw new Exception ();
          }
        }
        else {
          throw new Exception ();
        }
      }
      //Console.WriteLine (src);
      return (bytesDecoded);
    }

    public void Dispose () {
      if (_bitmap != null) {
        _bitmap.Dispose ();
      }
    }
  }
}
